package com.example.demo.ribbon;

import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeUnit;

import com.google.common.collect.Lists;
import com.netflix.client.DefaultLoadBalancerRetryHandler;
import com.netflix.client.RetryHandler;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.BestAvailableRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.LoadBalancerBuilder;
import com.netflix.loadbalancer.LoadBalancerStats;
import com.netflix.loadbalancer.PingUrl;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.reactive.LoadBalancerCommand;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import rx.Observable;

public class URLConnectionLoadBalancer {

    private final ILoadBalancer loadBalancer;

    // retry handler that does not retry on same server, but on a different server
    private final RetryHandler retryHandler = new DefaultLoadBalancerRetryHandler(0, 1, true);

    private LoadBalancerCommand<String> command;

    public URLConnectionLoadBalancer(List<Server> serverList) {
        IRule rule = new BestAvailableRule();
        IPing ping = new PingUrl(false, "/");
        loadBalancer = LoadBalancerBuilder.newBuilder()
                .withRule(rule)
                .withPing(ping)
                .buildFixedServerListLoadBalancer(serverList);
    }

    public String call(final String path, String content) throws Exception {
        if (command == null) {
            command = LoadBalancerCommand.<String>builder()
                    .withRetryHandler(retryHandler)
                    .withLoadBalancer(loadBalancer)
                    .build();
        }
        return command.submit((server) -> {
            try {
                URL url = new URL(server.getScheme() + server.getHost() + ":" + server.getPort() + path);
                OkHttpClient.Builder cliBuilder = new OkHttpClient.Builder();
                cliBuilder.connectTimeout(20, TimeUnit.SECONDS);
                cliBuilder.readTimeout(30, TimeUnit.SECONDS);
                OkHttpClient okHttpClient = cliBuilder.build();
                RequestBody body = RequestBody.create(MediaType.parse("application/json"), content);
                Request.Builder builder = new Request.Builder();
                builder.url(url).post(body);
                Call call = okHttpClient.newCall(builder.build());
                Response response = call.execute();
                if (response.code() != 200) {
                    throw new Exception("" + response.code());
                }
                return Observable.just(response.body().string());
            } catch (Exception e) {
                return Observable.error(e);
            }
        }).toBlocking().first();
    }

    public LoadBalancerStats getLoadBalancerStats() {
        return ((BaseLoadBalancer) loadBalancer).getLoadBalancerStats();
    }

    public static void main(String[] args) throws Exception {
        URLConnectionLoadBalancer urlLoadBalancer = new URLConnectionLoadBalancer(Lists.newArrayList(
                new Server("http://", "dlr-data-004.service.dl.data.autohome.com.cn", 80),
                new Server("http://", "dlr-data-008.service.dl.data.autohome.com.cn", 80)));
        String res = urlLoadBalancer.call("/gpu/invoice/classify/v2", "{\"trade_no\":\"1111\",\"invoice_url\":\"http://private2.autoimg.cn/dealer/ics/20180527081250193a23ad1ee.jpg\"}");
        System.out.println(res);
        System.out.println(urlLoadBalancer.getLoadBalancerStats());
    }
}